package com.file.parser;


import com.file.bo.*;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.NurminenDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 支付宝理财资产证明解析
 * @author anyspa
 */

@Slf4j
public class AlipayAssetPdfParser extends BasePdfParser {


    public ResponseData<String> parseAlipayAssetPdfToJson(String daId, String filePath) {
        log.info("parseAlipayAssetPdfToJson started, daId:{}", daId);
        String json = null;

        try {
            Boolean isAssetProof = isAlipayAssetProof(filePath);
            if (isAssetProof) {
                AlipayAssetProof alipayAssetProof = parseAlipayAssetProofPdf(filePath);
                json = JsonUtils.convertObjectToJson(alipayAssetProof);
            } else {
                AlipayAssetTransaction alipayAssetTransaction = parseAlipayAssetTransactionPdf(filePath);
                json = JsonUtils.convertObjectToJson(alipayAssetTransaction);
            }
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseAlipayAssetPdfToJson failed", e);
            return new ResponseData<>(json, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseAlipayAssetPdfToJson completed, daId:{}", daId);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    public boolean isAlipayAssetProof(String filePath) {
        String headerText = parsePdfHeaderText(filePath);
        // 蚂蚁（杭州）基金销售有限公司基金（含资产管理计划）资产证明
        if (headerText.contains("基金（含资产管理计划）资产证明")) {
            return true;
        }
        // 蚂蚁（杭州）基金销售有限公司基金（含资产管理计划）交易明细
        else if (headerText.contains("基金（含资产管理计划）交易明细")) {
            return false;
        }
        throw new RuntimeException("the file type is not supported");
    }

    private AlipayAssetProof parseAlipayAssetProofPdf(String filePath) {
        AlipayAssetProof alipayAssetProof = parseAlipayAssetProofHeader(filePath);

        parseAlipayAssetProofDetail(filePath, alipayAssetProof);

        return alipayAssetProof;
    }

    private AlipayAssetTransaction parseAlipayAssetTransactionPdf(String filePath) {
        AlipayAssetTransaction alipayAssetTransaction = parseAlipayAssetTransactionHeader(filePath);

        parseAlipayAssetProofTransactionDetail(filePath, alipayAssetTransaction);

        // 处理一条交易夸页的case
        dealTransactionDetailCrossPageCase(alipayAssetTransaction);

        return alipayAssetTransaction;
    }

    private AlipayAssetProof parseAlipayAssetProofHeader(String filePath) {
        AlipayAssetProof alipayAssetProof = new AlipayAssetProof();
        String headerText = parsePdfHeaderText(filePath);
        String name = headerText.substring(headerText.indexOf("兹证明客户") + 5, headerText.indexOf("先生/女士"));
        String idNoStr = headerText.substring(headerText.indexOf("身份证号码") + 5, headerText.indexOf("在我公司代理销售"));
        String idNo = idNoStr.substring(0, idNoStr.indexOf("，"));
        String assetTotal = headerText.substring(headerText.indexOf("合计约为") + 4, headerText.indexOf("元（大写"));
        String number = headerText.substring(headerText.indexOf("编号：") + 4, headerText.indexOf("蚂蚁（杭州）基金销售有限公司"));

        String footerText = parsePdfPageTextByPageNumber(filePath, getPdfPageNumber(filePath));
        String text = footerText.substring(footerText.lastIndexOf("以基金注册登记机构的记录为准。") + 15).trim();
        Pattern pattern = Pattern.compile("\\d{4}年\\d{2}月\\d{2}日");
        Matcher matcher = pattern.matcher(text);
        if (matcher.find()) {
            alipayAssetProof.setIssuingCompany(text.substring(0, matcher.start()));
            alipayAssetProof.setIssuingDate(matcher.group());
        }

        alipayAssetProof.setName(name);
        alipayAssetProof.setIdNo(idNo);
        alipayAssetProof.setAssetTotal(assetTotal);
        alipayAssetProof.setNumber(number);
        return alipayAssetProof;
    }

    private void parseAlipayAssetProofDetail(String filePath, AlipayAssetProof alipayAssetProof) {
        List<AlipayAssetProofInfo> alipayAssetProofInfos = new ArrayList<>();
        // 1. 读取文件
        File pdf = new File(filePath);

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {

            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            // SpreadsheetDetectionAlgorithm sea = new SpreadsheetDetectionAlgorithm();
            NurminenDetectionAlgorithm sea = new NurminenDetectionAlgorithm();

            Map<Integer, List<Rectangle>> detectedTables = new HashMap<>();

            // 4. 获取每页的PageIterator
            PageIterator pages = objectExtractor.extract();

            // 5. 解析每页的Rectangle(table的位置)
            while (pages.hasNext()) {
                Page page = pages.next();
                List<Rectangle> tablesOnPage = sea.detect(page);
                if (tablesOnPage.size() > 0) {
                    detectedTables.put(page.getPageNumber(), tablesOnPage);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm bea = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : detectedTables.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());

                // 默认每页只有一个表格，因此获取第0个rectangle
                Rectangle rectangle = entry.getValue().get(0);
                rectangle.setBottom(rectangle.getBottom() + 5);
                Page area = page.getArea(rectangle);

                List<Table> tableList = bea.extract(area);

                // 解析每一個table
                tableList.forEach(table -> {
                    if (table.getColCount() > 1) {
                        for (int i = 0; i < table.getRowCount(); i++) {
                            if (Objects.nonNull(table.getCell(i, 0).getText())) {
                                if (table.getCell(i, 0).getText().contains("序号") || table.getCell(i, 1).getText().contains("序号")) {
                                    continue;
                                }
                                AlipayAssetProofInfo alipayAssetProofInfo = getAlipayAssetInfoByTable(table, i);
                                if (Objects.nonNull(alipayAssetProofInfo)) {
                                    alipayAssetProofInfos.add(alipayAssetProofInfo);
                                }
                            }
                        }
                    }
                });
            }
            alipayAssetProof.setAlipayAssetProofInfoList(alipayAssetProofInfos);
        }  catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private AlipayAssetProofInfo getAlipayAssetInfoByTable(Table table, int i) {
        AlipayAssetProofInfo alipayAssetProofInfo = null;
        if (table.getColCount() == 8) {
            alipayAssetProofInfo = new AlipayAssetProofInfo();
            alipayAssetProofInfo.setSerialNum(table.getCell(i, 0).getText(false));
            alipayAssetProofInfo.setFundTransactionAccount(table.getCell(i, 1).getText(false));
            alipayAssetProofInfo.setFundName(table.getCell(i, 2).getText(false));
            alipayAssetProofInfo.setFundCode(table.getCell(i, 3).getText(false));
            alipayAssetProofInfo.setTotalShare(table.getCell(i, 4).getText(false));
            alipayAssetProofInfo.setAverageNAV(table.getCell(i, 5).getText(false));
            alipayAssetProofInfo.setUnitNetValueDate(table.getCell(i, 6).getText(false));
            alipayAssetProofInfo.setSubtotalOfAssets(table.getCell(i, 7).getText(false));
        } else if (table.getColCount() == 9) {
            alipayAssetProofInfo = new AlipayAssetProofInfo();
            alipayAssetProofInfo.setSerialNum(table.getCell(i, 1).getText(false));
            alipayAssetProofInfo.setFundTransactionAccount(table.getCell(i, 2).getText(false));
            alipayAssetProofInfo.setFundName(table.getCell(i, 3).getText(false));
            alipayAssetProofInfo.setFundCode(table.getCell(i, 4).getText(false));
            alipayAssetProofInfo.setTotalShare(table.getCell(i, 5).getText(false));
            alipayAssetProofInfo.setAverageNAV(table.getCell(i, 6).getText(false));
            alipayAssetProofInfo.setUnitNetValueDate(table.getCell(i, 7).getText(false));
            alipayAssetProofInfo.setSubtotalOfAssets(table.getCell(i, 8).getText(false));
        }
        return alipayAssetProofInfo;
    }

    private AlipayAssetTransaction parseAlipayAssetTransactionHeader(String filePath) {
        AlipayAssetTransaction alipayAssetTransaction = new AlipayAssetTransaction();
        String headerText = parsePdfHeaderText(filePath);
        String number = headerText.substring(headerText.indexOf("编号：") + 3, headerText.indexOf("蚂蚁（杭州）基金销售有限公司"));
        String name = headerText.substring(headerText.indexOf("兹证明客户") + 5, headerText.indexOf("，身份证号码"));
        String idNo = headerText.substring(headerText.indexOf("身份证号码：") + 6, headerText.indexOf("，在我公司代理销售"));
        alipayAssetTransaction.setNumber(number);
        alipayAssetTransaction.setName(name);
        alipayAssetTransaction.setIdNo(idNo);

        String footerText = parsePdfPageTextByPageNumber(filePath, getPdfPageNumber(filePath));
        String text = footerText.substring(footerText.lastIndexOf("以基金注册登记机构的记录为准。") + 15).trim();
        Pattern pattern = Pattern.compile("\\d{4}年\\d{2}月\\d{2}日");
        Matcher matcher = pattern.matcher(text);
        if (matcher.find()) {
            alipayAssetTransaction.setIssuingCompany(text.substring(0, matcher.start()));
            alipayAssetTransaction.setIssuingDate(matcher.group());
        }
        return alipayAssetTransaction;
    }

    private void parseAlipayAssetProofTransactionDetail(String filePath, AlipayAssetTransaction alipayAssetTransaction) {
        List<AlipayAssetTransactionInfo> alipayAssetTransactionInfos = new ArrayList<>();
        // 1. 读取文件
        File pdf = new File(filePath);

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {

            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            NurminenDetectionAlgorithm sea = new NurminenDetectionAlgorithm();
            Map<Integer, List<Rectangle>> detectedTables = new HashMap<>();

            // 4. 获取每页的PageIterator
            PageIterator pages = objectExtractor.extract();

            // 5. 解析每页的Rectangle(table的位置)
            while (pages.hasNext()) {
                Page page = pages.next();
                List<Rectangle> tablesOnPage = sea.detect(page);
                if (tablesOnPage.size() > 0) {
                    detectedTables.put(page.getPageNumber(), tablesOnPage);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm bea = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : detectedTables.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());

                // 默认每页只有一个表格，因此获取第0个rectangle
                Rectangle rectangle = entry.getValue().get(0);
                rectangle.setBottom(rectangle.getBottom() + 5);
                Page area = page.getArea(rectangle);

                List<Table> tableList = bea.extract(area);

                // 解析每一個table
                tableList.forEach(table -> {
                    if (table.getColCount() > 1) {
                        for (int i = 0; i < table.getRowCount(); i++) {
                            if (Objects.nonNull(table.getCell(i, 0).getText())) {
                                if (table.getCell(i, 0).getText().contains("订单号")) {
                                    continue;
                                }
                                AlipayAssetTransactionInfo alipayAssetTransactionInfo = getAlipayAssetTransactionInfoByTable(table, i);
                                alipayAssetTransactionInfos.add(alipayAssetTransactionInfo);
                            }
                        }
                    }
                });
            }
            alipayAssetTransaction.setAlipayAssetTransactionInfos(alipayAssetTransactionInfos);
        }  catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private AlipayAssetTransactionInfo getAlipayAssetTransactionInfoByTable(Table table, int i) {
        AlipayAssetTransactionInfo alipayAssetTransactionInfo = new AlipayAssetTransactionInfo();
        alipayAssetTransactionInfo.setOrderNum(table.getCell(i, 0).getText(false));
        alipayAssetTransactionInfo.setTransDate(table.getCell(i, 1).getText(false));
        alipayAssetTransactionInfo.setTransType(table.getCell(i, 2).getText(false));
        alipayAssetTransactionInfo.setFundName(table.getCell(i, 3).getText(false));
        alipayAssetTransactionInfo.setMutualFundName(table.getCell(i, 4).getText(false));
        alipayAssetTransactionInfo.setFundCode(table.getCell(i, 5).getText(false));
        alipayAssetTransactionInfo.setAppliedAmount(table.getCell(i, 6).getText(false));
        alipayAssetTransactionInfo.setAppliedShare(table.getCell(i, 7).getText(false));
        alipayAssetTransactionInfo.setConfirmedAmount(table.getCell(i, 8).getText(false));
        alipayAssetTransactionInfo.setConfirmedShare(table.getCell(i, 9).getText(false));
        alipayAssetTransactionInfo.setCommission(table.getCell(i, 10).getText(false));
        alipayAssetTransactionInfo.setConfirmedDate(table.getCell(i, 11).getText(false));
        return alipayAssetTransactionInfo;
    }

    private void dealTransactionDetailCrossPageCase(AlipayAssetTransaction alipayAssetTransaction) {
        List<AlipayAssetTransactionInfo> alipayAssetTransactionInfos = alipayAssetTransaction.getAlipayAssetTransactionInfos();
        List<AlipayAssetTransactionInfo> alipayAssetTransactionInfoList = new ArrayList<>();

        for (int i = 0; i < alipayAssetTransactionInfos.size(); i++) {
            // orderNum: 20200705001080012204360041986638
            if (alipayAssetTransactionInfos.get(i).getOrderNum().trim().length() == 32) {
                alipayAssetTransactionInfoList.add(alipayAssetTransactionInfos.get(i));
                continue;
            }

            if (alipayAssetTransactionInfos.get(i).getOrderNum().trim().length() < 32
                    && alipayAssetTransactionInfos.get(i + 1).getOrderNum().trim().length() < 32) {

                AlipayAssetTransactionInfo alipayAssetTransactionInfo = new AlipayAssetTransactionInfo();
                alipayAssetTransactionInfo.setOrderNum(alipayAssetTransactionInfos.get(i).getOrderNum().trim()
                        + alipayAssetTransactionInfos.get(i + 1).getOrderNum().trim());
                alipayAssetTransactionInfo.setTransDate(alipayAssetTransactionInfos.get(i).getTransDate().trim()
                        + alipayAssetTransactionInfos.get(i + 1).getTransDate().trim());
                alipayAssetTransactionInfo.setTransType(alipayAssetTransactionInfos.get(i).getTransType().trim()
                        + alipayAssetTransactionInfos.get(i + 1).getTransType().trim());
                alipayAssetTransactionInfo.setFundName(alipayAssetTransactionInfos.get(i).getFundName().trim()
                        + alipayAssetTransactionInfos.get(i + 1).getFundName().trim());
                alipayAssetTransactionInfo.setMutualFundName(alipayAssetTransactionInfos.get(i).getMutualFundName().trim()
                        + alipayAssetTransactionInfos.get(i + 1).getMutualFundName().trim());
                alipayAssetTransactionInfo.setFundCode(alipayAssetTransactionInfos.get(i).getFundCode().trim()
                        + alipayAssetTransactionInfos.get(i + 1).getFundCode().trim());
                alipayAssetTransactionInfo.setAppliedAmount(alipayAssetTransactionInfos.get(i).getAppliedAmount().trim()
                        + alipayAssetTransactionInfos.get(i + 1).getAppliedAmount().trim());
                alipayAssetTransactionInfo.setAppliedShare(alipayAssetTransactionInfos.get(i).getAppliedShare().trim()
                        + alipayAssetTransactionInfos.get(i + 1).getAppliedShare().trim());
                alipayAssetTransactionInfo.setConfirmedAmount(alipayAssetTransactionInfos.get(i).getConfirmedAmount().trim()
                        + alipayAssetTransactionInfos.get(i + 1).getConfirmedAmount().trim());
                alipayAssetTransactionInfo.setConfirmedShare(alipayAssetTransactionInfos.get(i).getConfirmedShare().trim()
                        + alipayAssetTransactionInfos.get(i + 1).getConfirmedShare().trim());
                alipayAssetTransactionInfo.setCommission(alipayAssetTransactionInfos.get(i).getCommission().trim()
                        + alipayAssetTransactionInfos.get(i + 1).getCommission().trim());
                alipayAssetTransactionInfo.setConfirmedDate(alipayAssetTransactionInfos.get(i).getConfirmedDate().trim()
                        + alipayAssetTransactionInfos.get(i + 1).getConfirmedDate().trim());
                alipayAssetTransactionInfoList.add(alipayAssetTransactionInfo);
                i ++;//NOSONAR
            }
        }
        alipayAssetTransaction.setAlipayAssetTransactionInfos(alipayAssetTransactionInfoList);
    }

    public static void main(String[] args) {
        AlipayAssetPdfParser alipayAssetPdfParser = new AlipayAssetPdfParser();
        String json = alipayAssetPdfParser.parseAlipayAssetPdfToJson("", "D:\\data\\file\\alipayAsset\\支付宝理财资产证明.pdf").getData();
        System.out.println(json);

        json = alipayAssetPdfParser.parseAlipayAssetPdfToJson("", "D:\\data\\file\\alipayAsset\\支付宝理财交易明细.pdf").getData();
        System.out.println(json);

        json = alipayAssetPdfParser.parseAlipayAssetPdfToJson("", "D:\\data\\file\\alipayAsset\\2023021417063798_2088622140128055.pdf").getData();
        System.out.println(json);

        json = alipayAssetPdfParser.parseAlipayAssetPdfToJson("", "D:\\data\\file\\alipayAsset\\20230215113027302_2088622140128055.pdf").getData();
        System.out.println(json);

        json = alipayAssetPdfParser.parseAlipayAssetPdfToJson("", "D:\\data\\file\\alipayAsset\\宋强华_20230411172344277_2088622140128055.pdf").getData();
        System.out.println(json);

    }
}
